/*!
自定义 定时器 future 
Waker唤醒任务

futures 在第一次被 poll 时无法完成是很常见的 。当发生这种情况时，futures 需要确保在准备好取得更多进展后再次对其进行轮询。
这是通过 Waker 类型完成的 。
每次轮询 futures 时，都会将其作为 “任务” 的一部分进行轮询。任务是已提交给执行者的顶级 futures。

Waker 每个都提供了一种 wake() 方法，可以用来告诉执行者他们的相关任务应该被唤醒。当 wake() 调用时，执行程序知道与该关联的任务
Waker 已准备好进行，并且应该再次轮询其 future。

Waker 还实现了 clone() 以便复制和存储它们。

让我们尝试使用 Waker 实现一个简单的计时器。

!*/
use {
    std::{
        future::Future,
        pin::Pin,
        sync::{Arc, Mutex},
        task::{Context, Poll, Waker},
        thread,
        time::Duration,
    },
};

/// `future`与等待线程之间的共享状态
struct SharedState {
    /// 用于判断sleep的时间是不是已经过了
    completed: bool,

    /// 任务的唤醒者 `TimerFuture` 正在上面运行.
    /// 线程能够使用这个设置`completed = true`之后去调用
    /// `TimerFuture`的任务来唤醒, 观察 `completed = true`, 并前进
    waker: Option<Waker>,
}

///计时器
struct TimeFuture {
    shared_state: Arc<Mutex<SharedState>>,
}

///实现Future
impl Future for TimeFuture {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // 注意shared_state 并去看计时器（timer）是不是已经完成（completed）了
        let mut shared_state = self.shared_state.lock().unwrap();
        if shared_state.completed {
            println!("Ready-----------------------");
            Poll::Ready(())
        }else {
            //执行时如果是Pending(未完成)，则设置waker（唤醒器）
            // 设置唤醒器，以便线程在计时器（timer）完成的时候可以唤醒当前任务
            // 确定 future已经再一次被轮询了，并且看`completed = true`.
            //
            //重要的是，我们必须在每次轮询 Future 时更新 Waker，因为 Future 可能已经转移到另一个不同的任务与 Waker。
            // Future 被轮询之后在任务间传递时会发生这种情况。
            //
            // 注意：可以使用 `Waker::will_wake`这个函数来检查
            // 但是为了简单起见，我们忽略了这个。
            shared_state.waker = Some(cx.waker().clone());
            println!("Pending------------------");
            Poll::Pending
        }
    }
}

impl TimeFuture {
    /// 创建一个新的`TimerFuture` 将在提供timeout之后完成
    pub fn new(duration: Duration) -> Self {
        let shared_state = Arc::new(Mutex::new(SharedState {
            completed: false,
            waker: None,
        }));
        // 引发新的线程
        let thread_shared_state = shared_state.clone();
        thread::spawn(move || {
            thread::sleep(duration);
            let mut shared_state = thread_shared_state.lock().unwrap();
            // 表示计时器已经完成并唤醒最后一个拥有被轮询过的future的任务，如果它存在的话
            shared_state.completed = true;
            //拿到唤醒器
            if let Some(waker) = shared_state.waker.take() {
                println!("wake-----------------");
                //唤醒，执行与当前唤醒器相关的任务
                waker.wake()
            }
        });
        TimeFuture { shared_state }
    }
}

#[test]
pub fn time_task_demo(){
    // 我们现在还没有实现调度器，所以要用一下futues库里的一个调度器。
    //开始的时候，定时10s事件还未完成，处在Pending状态，这时要告诉这个任务后面就绪后怎么唤醒去调度执行。
    // 等10s后，定时事件完成了，通过前面的设置的Waker，唤醒这个Future任务去调度执行
    let future = TimeFuture::new(Duration::new(10, 0));
    futures::executor::block_on(future);
}



